# !/usr/bin/env python
# encoding: utf-8


"""
  @author: gaogao
  @file: probe_station_task.py
  @QThread: 2022/11/9 11:54
  @desc:
"""

from PyQt5.QtCore import QObject, QWaitCondition, QMutex, pyqtSignal, QThread
from ATS.proberdriver.cascade_prober import CascadeProber
from ATS.application.LASER_App.L8164B_App import L8164B_App
import random
from collections import namedtuple
from utils.log_util import loggings
from utils.save_data_2_file import save_spot_data_2_file


class ProbeStationTask(QObject):
    TestSignal = pyqtSignal(int)
    send_map = pyqtSignal(object)
    Stop = pyqtSignal(int)
    End = pyqtSignal(int)
    err_signal = pyqtSignal(object)
    wafer_result_signal = pyqtSignal(object, object)

    def __init__(self, probe_address, test_seq=None, subdie_list=None,
                 probe_order_list=None):
        super().__init__()
        self.cond = QWaitCondition()
        self.mutex = QMutex()
        self.test_seq = test_seq
        self.subdie_list = subdie_list
        self.ml = None
        self._isPause = False
        self.is_go_next_subdie = False
        self.pro_address = probe_address
        self.lower_limit = -50  # 对光阈值下限
        self.delay_time = 200  # 单位为毫秒
        self.probe_delay = 200  # 抬针延迟时间，单位为毫秒
        self.probe_position_value = 10
        self.flag = True
        self.singal_pd_dark = False
        self.probe_order_list = probe_order_list
        # self.probe_state_dict = {test.subdie:test.probe_state_dict for test in test_seq}
        # self.probe_state_dict = self.test_seq[0].test_set.probe_state_dict
        test_pro_list = set([test.test_pro for test in test_seq])
        test_subdie = set([test.subdie for test in test_seq])
        if len(test_pro_list) == 1 and list(test_pro_list)[0] == "MPD_I_dark":
            self.singal_pd_dark = True
            L8164B_App("SS3").output_off()
        else:
            L8164B_App("SS3").output_on()
        self.test_index = sorted([self.subdie_list.index(test_s) + 1 for test_s in test_subdie])
        self.cp = CascadeProber(self.pro_address)
        self.map_info = namedtuple("map_info", "DieX,DieY,CurSite,CurDie,DiesCount,SubdieLabel")

    def send_message_to_gui(self):
        result = self.cp.read_map_position()
        self.wafer_die_count = int(self.cp.get_wafer_info().DiesCount)
        self.subdie_label_list = []
        for i in range(result.LastSiteIndex):
            if self.cp.get_subdie_status(i) == "E":
                self.subdie_label_list.append(i)
        self.wafer_result_signal.emit(self.wafer_die_count, self.subdie_label_list)

    def separation_move_hone(self, probe_reverse_list):
        if len(probe_reverse_list):
            loggings.info("probe stop")
            self.separation_probes_and_chuck()
            self.move_probes_to_home(probe_reverse_list)

    def separation_probes_and_chuck(self):
        self.separation_probes()
        self.separation_chuck()

    def find_area_recenter(self):
        self.find_optical_probes_height()
        self.cp.area_scan()
        self.recenter_optical_probes()
        as_result = self.cp.area_scan()
        if float(as_result[-1]) < self.lower_limit and float(as_result[-2]) < self.lower_limit:
            self.err_signal.emit("Area Scan没有找到光")

    def set_electric_probes_home(self):
        self.cp.set_probe_home(1)
        self.cp.set_probe_home(2)

    def contact_single_probe(self, probe_index=1):
        self.cp.move_probe_contact(probe_index)

    def separation_single_probe(self, probe_index=1):
        self.cp.move_probe_separation(probe_index)

    def recenter_optical_probes(self):
        self.recenter_optical_probe("W")
        self.recenter_optical_probe("E")

    def recenter_optical_probe(self, optical_probe_alias: str):
        self.cp.recenter_optical_probe(optical_probe_alias)
        QThread.msleep(self.delay_time)

    def find_optical_probes_height(self):
        self.find_optical_probe_height("W")
        self.find_optical_probe_height("E")

    def find_optical_probe_height(self, optical_probe_alias: str):
        self.cp.find_optical_probe_height(optical_probe_alias)
        QThread.msleep(self.delay_time)

    def set_optical_probes_home(self):
        self.set_optical_probe("W")
        self.set_optical_probe("E")

    def set_optical_probe(self, optical_probe_alias: str):
        self.cp.set_optical_probe_home(optical_probe_alias)
        QThread.msleep(self.delay_time)

    def move_probes_to_home(self, probe_list):
        if len(probe_list):
            for probe in probe_list:
                if "P" in probe:
                    self.cp.move_probe_home(int(probe[-1]))
                else:
                    self.cp.move_optical_probe_home(probe)

    def set_optical_probes_height(self):
        self.set_optical_probe_height("W")
        self.set_optical_probe_height("E")

    def set_optical_probe_height(self, optical_probe_alias: str):
        self.cp.set_optical_probe_height(optical_probe_alias)
        QThread.msleep(self.delay_time)

    def contact_probes(self):
        self.contact_optical_single("W")
        self.contact_optical_single("E")
        if self.probe_state_dict["P1"]:
            self.contact_single_electricity_probe(1)
        if self.probe_state_dict["P2"]:
            self.contact_single_electricity_probe(2)

    def contact_single_electricity_probe(self, probe_idx: int):
        self.cp.move_probe_contact(probe_idx)
        QThread.msleep(self.probe_delay)
        if self.cp.read_probe_status(probe_idx).PresetHeight == "S":
            self.cp.move_probe_contact(probe_idx)

    def contact_optical_single(self, optical_probe_alias: str):
        self.cp.move_optical_probe_height(optical_probe_alias)
        QThread.msleep(self.probe_delay)
        if self.cp.get_optical_probe_status(optical_probe_alias)[2] == "0":
            self.cp.move_optical_probe_height(optical_probe_alias)

    def separation_probes(self):
        self.separation_single_optical("W")
        self.separation_single_optical("E")
        self.separation_single_electricity_probe(1)
        self.separation_single_electricity_probe(2)

    def separation_single_electricity_probe(self, probe_idx: int):
        self.cp.move_probe_separation(probe_idx)
        QThread.msleep(self.probe_delay)
        if self.cp.read_probe_status(probe_idx).PresetHeight == "C":
            self.cp.move_probe_separation(probe_idx)

    def separation_single_optical(self, optical_probe_alias: str):
        self.cp.move_optical_separation_height(optical_probe_alias)
        QThread.msleep(self.probe_delay)
        if self.cp.get_optical_probe_status(optical_probe_alias)[2] == "1":
            self.cp.move_optical_separation_height(optical_probe_alias)

    def separation_chuck(self):
        self.cp.move_chuck_separation()

    def run(self):
        global probe_reverse_list
        try:
            self.send_message_to_gui()
            if self.ml is None:
                self.ml = QMutexLocker(self.mutex)
            if self.probe_order_list is None:
                self.probe_order_list = ["P1", "P2", "E", "W"]
            probe_reverse_list = list(reversed(self.probe_order_list))
            self.separation_probes()
            self.move_probes_to_home(probe_reverse_list)
            self.cp.go_to_wafer_home()
            self.cp.move_chuck_contact()
            self.cp.step_first_die()
            if not self.singal_pd_dark:
                self.set_electric_probes_home()
                self.contact_recenter_home()
            # while self.flag:
            for die_number in range(self.wafer_die_count):
                if self.flag:
                    self.cond_wait()
                    if die_number != 0:
                        if not self.singal_pd_dark:
                            self.contact_recenter_home()
                    for site in self.subdie_label_list:
                        if self.flag:
                            self.cond_wait()
                            if len(self.subdie_label_list) > 1 and site != 0:
                                self.cp.step_next_subdie(site)
                                if not self.singal_pd_dark:
                                    self.contact_recenter_home()
                            velox_subdie_label = self.cp.get_subdie_label(site)
                            rsp = self.cp.read_map_position()
                            self.send_map.emit(
                                self.map_info(rsp.DieX, rsp.DieY, rsp.CurSite, rsp.CurDie, rsp.DiesCount,
                                              velox_subdie_label))
                            # for item in range(1, self.sip_subdie_number + 1):
                            if not self.singal_pd_dark:
                                for item in self.test_index:
                                    if self.flag:
                                        self.cond_wait()
                                        for probe in self.probe_order_list:
                                            if item != 1:
                                                self.cp.move_optical_subdie_pos(item, probe)
                                        self.find_optical_probes_height()
                                        number = 0
                                        as_result0 = self.cp.area_scan()
                                        while True:
                                            as_result = self.cp.area_scan()
                                            delta2 = float(as_result[-1]) - float(as_result0[-1])
                                            save_spot_data_2_file(r"F:\measurement_data\area_scan_data\delta.csv",
                                                                  "delta2_data", f"{delta2}")

                                            if float(as_result[-1]) < self.lower_limit and float(
                                                    as_result[-2]) < self.lower_limit:
                                                if number < 1:
                                                    number += 1
                                                    continue
                                                else:
                                                    # self.is_go_next_subdie = True
                                                    # self.err_signal.emit("Area Scan没有找到光")
                                                    self.cp.bin_map_die(1)
                                                    break
                                            else:
                                                # self.is_go_next_subdie = False
                                                break
                                        # if not self.is_go_next_subdie:
                                        if self.flag:
                                            self.TestSignal.emit(1)
                                            self.pause()
                                            self.cond_wait()
                                        else:
                                            self.separation_move_hone(probe_reverse_list)
                                            return
                                    else:
                                        loggings.info("probe_move")
                                        self.separation_move_hone(probe_reverse_list)
                                        return
                                self.separation_probes()
                                self.move_probes_to_home(probe_reverse_list)
                                # self.contact_probes()
                            else:
                                self.contact_single_probe()
                                self.TestSignal.emit(1)
                                self.pause()
                                self.cond_wait()
                        else:
                            loggings.info("subdie_move")
                            self.separation_move_hone(probe_reverse_list)
                            return
                    # 此处使用step_to_die(die_num),移动到指定的die_num
                    self.cp.step_next_die()
                    # self.cp.step_to_die(die_num)
                else:
                    loggings.info("die_move")
                    self.separation_move_hone(probe_reverse_list)
                    return
            self.ml.unlock()
        except Exception as e:
            try:
                if "703" in str(e):
                    self.End.emit(1)
                else:
                    self.err_signal.emit(str(e))
                loggings.error(f"ProbeStationThread,{e}")
                self.separation_probes_and_chuck()
                if probe_reverse_list and len(probe_reverse_list) == 4:
                    self.move_probes_to_home(probe_reverse_list)
                else:
                    self.probes_move_home()
                self.separation_chuck()
            except Exception as e:
                loggings.error(f"ProbeStationThread_separation_probes_and_chuck,{e}")
                self.err_signal.emit(str(e))
        finally:
            try:
                self.separation_probes_and_chuck()
                if probe_reverse_list and len(probe_reverse_list) == 4:
                    self.move_probes_to_home(probe_reverse_list)
                else:
                    self.probes_move_home()
                if self.ml:
                    self.ml.unlock()
            except Exception as e:
                loggings.error(f"ProbeStationThread_separation_probes_and_chuck,{e}")
            L8164B_App("SS3").output_off()

    def contact_recenter_home(self):
        self.contact_probes()
        self.find_area_recenter()
        self.set_optical_probes_home()

    def cond_wait(self):
        if self._isPause:
            self.cond.wait(self.ml.mutex())

    def resume(self):
        self._isPause = False
        QThread.msleep(200)
        self.cond.wakeAll()

    def stop_sip_tools(self):
        self.cp.stop_sip_tools()

    def pause(self):
        self._isPause = True

    def cancel(self):
        self.flag = False
        self._isPause = False
